module Res

importall Mat, Geo, Sec, Ele, Bc, Ela

export Result,
        FieldResult, HistResult, 
        NodeResult, EigenResult, 
        setDomain, printResult, saveResult

abstract Result
abstract FieldResult <: Result
abstract HistResult <: Result

type EigenResult <: FieldResult
    
    domain::Domain
    order::Int64
    omega::Float64
    freq::Float64
    modalShape::Vector{Float64}

    function EigenResult(domain::Domain,order::Int64)
        omega = 1.0
        freq = 1.0
        modalShape = zeros(domain.nActiveDof)
        return new(domain,order,omega,freq,modalShape)
    end
end

function setDomain(res::EigenResult)
    res.domain.linalgsys.dU = res.modalShape
    getSolution(res.domain)
end

function printResult(res::EigenResult)
    
    v1,v2,v3 = res.order,res.omega,res.freq
    @printf("%8d    %12.6f    %12.6f\n",v1,v2,v3)
end

function saveResult(res::FieldResult,fmt::String="gmsh")

    if fmt == "gmsh"
        writeGmsh(res)
    else
        nothing
    end
end

function writeGmsh(res::EigenResult)

    filename = "$(res.domain.name)_modal_$(res.order).msh"
    file = open(filename,"w")
    setDomain(res)
    gmshHead = "\$MeshFormat\r\n2.8 0 8\r\n\$EndMeshFormat\r\n"
    write(file,gmshHead)
    write(file,"\$NodeData\r\n")
    write(file,"1\r\n\"Mode $(res.order), freq = $(res.freq) Hz\"\r\n")
    write(file,"1\r\n$(res.order)\r\n")
    write(file,"3\r\n0\r\n3\r\n$(res.domain.nNode)\r\n")

    for node in values(res.domain.Nodes)
        u1 = node.disp[1]
        u2 = node.disp[2]
        if res.domain.dim == 3
            u3 = node.disp[3]
        else
            u3 = 0.0
        end
        write(file,"$(node.tag) $u1 $u2 $u3\r\n")
    end
    write(file,"\$EndNodeData\r\n")

    close(file)
end

type NodeResult <: HistResult
    
    domain::Domain
    node::Node
    fieldTag::Int64
    dofTag::Int64
    value::Vector{Float64}

    NodeResult(domain::Domain,nodeTag::Int64,fieldTag::Int64,dofTag::Int64) = new(domain,domain.node[nodeTag],fieldTag,dofTag,Float64[])
end

function appendResult(res::NodeResult)
    if res.fieldTag == 1
        push!(res.value,res.node.disp[res.dofTag])
    elseif res.fieldTag == 2
        push!(res.value,res.node.react[res.dofTag])
    end
end

function +(res1::HistResult,res2::HistResult)
    res = deepcopy(res1)
    res.value = res1.value.+res2.value
    return res
end

function -(res1::HistResult,res2::HistResult)
    res = deepcopy(res1)
    res.value = res1.value.-res2.value
    return res
end

function len(res::HistResult)
    return length(res.value)
end

end
